package org.bilinc.gz001;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;

import java.io.*;
import java.util.Calendar;

/**
 * Created with IntelliJ IDEA.
 * User: computer
 * Date: 20.11.12
 * Time: 21:33
 * To change this template use File | Settings | File Templates.
 */
public class ReportWriter {
    private static ReportWriter mSelf;
    public static final String VV = "вв";
    private static final String V = "в";
    private static final String DD = "дд";
    private static final String D = "д";
    private static final String ENG_O = "o";
    private static final String RUS_O = "о";
    private static final int SAT = 6;
    private static final String TEMPLATE_NAME = "wb.xls";
    private static final String EXT = ".xls";
    private static final String START_APP_CMD = "cmd /c start ";

    private InputStream mInputStream;
    private Workbook mWorkBook;
    private Sheet mSheet;
    private String mFileName;

    public static synchronized ReportWriter getInstance() {
        if (mSelf == null) {
            mSelf = new ReportWriter();
        }
        return mSelf;
    }

    public void writeReport(final String fileName,
                            final String otdel,
                            final String tabN,
                            final String city,
                            final String fio,
                            final Object[] calendar) throws IOException, InvalidFormatException {
        if (fileName != null) {
            mFileName = fileName;
        } else if (tabN != null) {
            mFileName = tabN;
        }

        read();
        writeReportData(otdel, tabN, city, fio, calendar);
        recalculate();
        save(mFileName);
        Runtime.getRuntime().exec(START_APP_CMD + mFileName + EXT);
    }

    private void read() throws IOException, InvalidFormatException {
        mInputStream = new FileInputStream(TEMPLATE_NAME);
        mWorkBook = WorkbookFactory.create(mInputStream);
        mSheet = mWorkBook.getSheetAt(0);
    }

    private void save(final String fileName) throws IOException {
        FileOutputStream fileOut = new FileOutputStream(fileName + EXT);
        mWorkBook.write(fileOut);
        fileOut.close();
    }

    private void recalculate() {
        FormulaEvaluator evaluator = mWorkBook.getCreationHelper().createFormulaEvaluator();
        for (int sheetNum = 0; sheetNum < mWorkBook.getNumberOfSheets(); sheetNum++) {
            Sheet sheet = mWorkBook.getSheetAt(sheetNum);
            for (Row r : sheet) {
                for (Cell c : r) {
                    if (c.getCellType() == Cell.CELL_TYPE_FORMULA) {
                        evaluator.evaluateFormulaCell(c);
                    }
                }
            }
        }
    }

    private void writeReportData(String otdel, String tabN, String city, String fio, Object[] calendar) throws IOException, InvalidFormatException {
        //city
        writeString(city, 2, 8);
        //tabN
        writeString(tabN, 3, 8);
        //otedel
        writeString(fio, 4, 12);
        // fio
        writeString(otdel, 5, 1);

        for (int i = 0; i < calendar.length; i++) {
            int month = Utils.getMonthByYearDay(i);
            int day = Utils.getMonthDayByYearDay(i);
            boolean isHoliday = Utils.isHoliday(i);
            boolean isWeekend = ((i + 1) % SAT == 0);

            switch (month) {
                case Calendar.JANUARY:
                    writeDayType((String) calendar[i], 9, day);
                    break;
                case Calendar.FEBRUARY:
                    writeDayType((String) calendar[i], 10, day);
                    break;
                case Calendar.MARCH:
                    writeDayType((String) calendar[i], 11, day);
                    break;
                case Calendar.APRIL:
                    writeDayType((String) calendar[i], 13, day);
                    break;
                case Calendar.MAY:
                    writeDayType((String) calendar[i], 14, day);
                    break;
                case Calendar.JUNE:
                    writeDayType((String) calendar[i], 15, day);
                    break;
                case Calendar.JULY:
                    writeDayType((String) calendar[i], 17, day);
                    break;
                case Calendar.AUGUST:
                    writeDayType((String) calendar[i], 18, day);
                    break;
                case Calendar.SEPTEMBER:
                    writeDayType((String) calendar[i], 19, day);
                    break;
                case Calendar.OCTOBER:
                    writeDayType((String) calendar[i], 21, day);
                    break;
                case Calendar.NOVEMBER:
                    writeDayType((String) calendar[i], 22, day);
                    break;
                case Calendar.DECEMBER:
                    writeDayType((String) calendar[i], 23, day);
                    break;
            }
        }
    }

    private void writeString(String val, int rowN, int colN) {
        if (val != null) {
            Row row = mSheet.getRow(rowN);
            Cell cell = row.getCell(colN);
            cell.setCellType(Cell.CELL_TYPE_STRING);
            cell.setCellValue(val);
        }
    }

    private void writeDayType(String val, int rowN, int colN) {
        if (val != null) {
            Row row = mSheet.getRow(rowN);
            Cell cell = row.getCell(colN);
            if (val.equals(ENG_O) ||
                    val.equals(RUS_O) ||
                    val.equals(VV) ||
                    val.equals(V) ||
                    val.equals(DD) ||
                    val.equals(D) ||
                    val.equals("")) {
                cell.setCellType(Cell.CELL_TYPE_STRING);
                cell.setCellValue(val);

            } else {
                cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                cell.setCellValue(Integer.valueOf(val));
            }
        }
    }


}
